/*
 * Copyright 2022 The Open Islands Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.openislands.oi.config.datasource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;
import java.util.Properties;

public interface DBPropertiesParser {
    // connection driver
    String DRIVER = "spring.datasource.driver-class-name";
    // connection url
    String URL = "spring.datasource.url";
    // user name
    String USERNAME = "spring.datasource.username";
    // user password
    String USER_PW_KEY = "spring.datasource.password";
    // initial connections number size
    String INITIAL_SIZE = "spring.datasource.initial-size";
    // maximum number of active connections
    String MAX_ACTIVE = "spring.datasource.max-active";
    // maximum number of idle connections
    String MAX_IDLE = "spring.datasource.max-idle";
    // minimum number of idle connections
    String MIN_IDLE = "spring.datasource.min-idle";
    // maximum time to live for a connection, in milliseconds
    String MAX_LIFETIME = "spring.datasource.max-lifetime";
    // maximum wait time to wait for the connection to return, in milliseconds
    String MAX_WAIT = "spring.datasource.max-wait";
    // maximum number of connections, including active and idle connections
    String MAXIMUM_POOL_SIZE = "spring.datasource.maximum-pool-size";
    // minimum time after which an idle connection can be cleared
    String MIN_EVICTABLE_IDLE_TIME_MILLIS = "spring.datasource.min-evictable-idle-time-millis";
    // connection timeout, in milliseconds
    String CONNECTION_TIMEOUT = "spring.datasource.connection-timeout";
    // time at which the connection should be discarded, in milliseconds
    String REMOVE_ABANDONED_TIMEOUT = "spring.datasource.remove-abandoned-timeout";

    /***
     * parse load source config to target
     * @param source    parse load source
     * @param target    set target
     */
    void loadConfig(Properties source, Properties target);

    static void load(Object name, Properties source, Properties target) {
        if ("sqlite".equals(name)) {
            new Sqlite().loadConfig(source, target);
            return;
        }
        new Mysql().loadConfig(source, target);
    }

    /***
     * mysql properties parser
     */
    class Mysql implements DBPropertiesParser {
        private static final Logger log = LoggerFactory.getLogger(DBPropertiesParser.class);

        @Override
        public void loadConfig(Properties source, Properties target) {
            final Object name = source.get("database.name");
            final Object user = source.get("database.user");
            final Object passwd = source.get("database.passwd");
            final Object host = source.get("database.host");
            final Object port = source.get("database.port");
            final Object maxConnections = source.get("database.max_connections");
            final Object staleTimeout = source.get("database.stale_timeout");

            target.setProperty(DRIVER, "com.mysql.cj.jdbc.Driver");
            if (!(Objects.isNull(host) || Objects.isNull(port) || Objects.isNull(name))) {
                target.setProperty(URL, "jdbc:mysql://" + host + ":" + port + "/" + name + "" +
                        "?characterEncoding=utf8&characterSetResults=utf8&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8&useSSL=true");
                log.info("mysql: " + target.getProperty(URL));
            }

            if (Objects.nonNull(user)) {
                target.put(USERNAME, user);
            }
            if (Objects.nonNull(passwd)) {
                target.put(USER_PW_KEY, passwd);
            }
            if (Objects.nonNull(maxConnections)) {
                target.put(MAXIMUM_POOL_SIZE, maxConnections);
            }
            if (Objects.nonNull(staleTimeout)) {
                target.put(REMOVE_ABANDONED_TIMEOUT, staleTimeout);
            }
        }
    }

    /***
     * sqlite properties parser
     */
    class Sqlite implements DBPropertiesParser {

        @Override
        public void loadConfig(Properties source, Properties target) {
            final Object name = source.get("database.name");
            final Object maxConnections = source.get("database.max_connections");
            final Object staleTimeout = source.get("database.stale_timeout");

            target.setProperty(DRIVER, "org.sqlite.JDBC");
            if (Objects.nonNull(name)) {
                target.setProperty(URL, "jdbc:sqlite:" + name + ".db");
            }
            if (Objects.nonNull(maxConnections)) {
                target.put(MAXIMUM_POOL_SIZE, maxConnections);
            }
            if (Objects.nonNull(staleTimeout)) {
                target.put(REMOVE_ABANDONED_TIMEOUT, staleTimeout);
            }
        }
    }
}
